package com.nihao001.parse.reader;

import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.jsoup.Connection;
import org.jsoup.Connection.Response;
import org.jsoup.Jsoup;
import org.jsoup.helper.DataUtil;
import org.jsoup.helper.HttpConnection;

import com.nihao001.parse.exception.NetworkException;
import com.nihao001.parse.exception.ParseException;

/**
 * 
 * <p>
 * Description:基于jsoup的reader
 * </p>
 * 
 * <p>
 * Author: wang xing yue
 * </p>
 * <p>
 * Date :Nov 14, 2013
 * </p>
 * 
 */

public class DefaultReader implements Reader {

	private static final long SLEEP_TIME = 1000;

	private static final int TRY_COUNT = 3;

	private String proxyHost = null;

	private int proxyPort = -1;

	@Override
	public Response get(String url, String requestEncode,
			Map<String, String> data, Map<String, String> cookie,
			Map<String, String> headers) throws ParseException {
		try {
			return request(url, requestEncode, Connection.Method.GET, data,
					cookie, headers);
		} catch (NetworkException e) {
			throw new ParseException(e);
		}
	}

	@Override
	public Response post(String url, String requestEncode,
			Map<String, String> data, Map<String, String> cookie,
			Map<String, String> headers) throws ParseException {
		try {
			return request(url, requestEncode, Connection.Method.POST, data,
					cookie, headers);
		} catch (NetworkException e) {
			throw new ParseException(e);
		}
	}

	@Override
	public Response get(String url, Map<String, String> data,
			Map<String, String> cookie, Map<String, String> headers)
			throws ParseException {
		try {
			return request(url, Connection.Method.GET, data, cookie, headers);
		} catch (NetworkException e) {
			throw new ParseException(e);
		}
	}

	@Override
	public Response post(String url, Map<String, String> data,
			Map<String, String> cookie, Map<String, String> headers)
			throws ParseException {
		try {
			return request(url, Connection.Method.POST, data, cookie, headers);
		} catch (NetworkException e) {
			throw new ParseException(e);
		}
	}

	@Override
	public Response get(String url, Map<String, String> data,
			Map<String, String> cookie) throws ParseException {
		try {
			return request(url, Connection.Method.GET, data, cookie, null);
		} catch (NetworkException e) {
			throw new ParseException(e);
		}
	}

	@Override
	public Response post(String url, Map<String, String> data,
			Map<String, String> cookie) throws ParseException {
		try {
			return request(url, Connection.Method.POST, data, cookie, null);
		} catch (NetworkException e) {
			throw new ParseException(e);
		}
	}

	private Response request(String url, Connection.Method method,
			Map<String, String> data, Map<String, String> cookies,
			Map<String, String> headers) throws NetworkException {
		return request(url, DataUtil.defaultCharset, method, data, cookies,
				headers);
	}

	private Response request(String url, String requestEncode,
			Connection.Method method, Map<String, String> data,
			Map<String, String> cookies, Map<String, String> headers)
			throws NetworkException {
		HttpConnection conn = (HttpConnection) Jsoup.connect(url);

		// 设置reuqest encode
		conn.setRquestEncode(requestEncode);

		// 设置http请求方法
		conn.method(method);

		// 设置代理
		setProxy(conn);

		if (data != null && data.size() > 0) {
			conn.data(data);
		}
		if (cookies != null && cookies.size() > 0) {
			conn.cookies(cookies);
		}
		if (headers != null && headers.size() > 0) {
			for (Map.Entry<String, String> entry : headers.entrySet()) {
				conn.header(entry.getKey(), entry.getValue());
			}
		}

		Response response = null;
		// 尝试3次
		for (int i = 0; i < TRY_COUNT; i++) {
			try {
				response = conn.execute();

				// 没有异常直接调出for循环
				break;
			} catch (Exception e) {
				if (i == (TRY_COUNT - 1)) {
					throw new NetworkException(e);
				}
			}
			try {
				Thread.sleep(SLEEP_TIME);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		return response;
	}

	private void setProxy(HttpConnection conn) {
		if (!StringUtils.isEmpty(this.proxyHost) && this.proxyPort > 0) {
			conn.proxy(this.proxyHost, this.proxyPort);
		}
	}

	@Override
	public void resetProxy() {
		this.proxyHost = "";
		this.proxyPort = -1;
	}

	@Override
	public void setProxy(String proxyHost, int proxyPort) throws ParseException {
		this.proxyHost = proxyHost;
		this.proxyPort = proxyPort;
	}

}
